# a post or update from one of the sources. this is the central object in the system.
class Report < ActiveRecord::Base
  belongs_to(:source)
  has_many(:incident_reports)
  has_many(:incidents, :through => :incident_reports)
  
  before_create(:strip_html)
  #before_save(:check_for_duplicates)
  
  scope(:unmarked, where(:important => nil))
  
  include ActionView::Helpers::SanitizeHelper
  
  # returns paginated reports
  def self.all_by_page(page, conditions = "")
    paginate(:page => page, :per_page => 50, :conditions => conditions, :include => [:incidents, :source], :order => "reports.authored_at desc")
  end

  # returns the number of search hits for the given conditions
  def self.search_count(conditions)
    count(:conditions => conditions, :include => [:source])
  end
  
  # the number of reports created since the given time
  def self.count_in_last(time)
    count(:conditions => ["created_at >= ?", Time.now - time])
  end
  
  def self.batch(sid)
    where(:scanner_session_id => sid).order("authored_at")
  end
  
  # checks out a batch of reports to the given session ID
  def self.checkout_batch(sid)
    # check if the given session ID already has a batch
    unless find_by_scanner_session_id(sid)
      # set scanner_session_id for a set of recent reports
      connection.execute("update reports set scanner_session_id='#{sid}', scan_started_at='#{Time.now.utc.basic_format}'
        where scanner_session_id is null and important is null order by authored_at DESC, created_at DESC limit #{CONF.batch_size}")
    end
  end
  
  # releases a scanned batch
  def self.release_batch(sid)
    connection.execute("update reports set scanner_session_id = null where scanner_session_id='#{sid}'")
  end

  # releases all batches assigned more than a minute ago
  def self.release_old_batches
    cutoff = (Time.now.utc - 1.minute).basic_format
    connection.execute("update reports set scanner_session_id = null, scan_started_at = null where scan_started_at<='#{cutoff}'")
  end
  
  # updates the importance of and releases all records specified by yes and no arrays
  def self.update_and_release_batch(session_id, ids)
    finished_at = Time.now
    started_at = nil
    # run the update queries
    [:yes, :no].each do |type|
      unless ids[type].empty?
        where("id in (#{ids[type].join(',')})").each do |r| 
          # capture the scan start time
          started_at = r.scan_started_at unless !started_at.nil? || r.scan_started_at.nil?
          # update the report
          r.update_attributes(:important => type.to_s, :scanner_session_id => nil, :mark_reason => 'Manual')
        end
      end
    end
    # return scan time
    started_at ? finished_at - started_at : nil
  end

  # so searchtoken can borrow this sanitize function
  # TODO: find a cleaner way
  def self.sanitize_str(*args)
    sanitize_sql_array(args)
  end
  
  # latest report (by author date) in the system
  def self.latest(conditions)
    find(:first, :conditions => conditions, :order => "authored_at desc")
  end
  
  def characteristic
    words = []
    # search word by word until target number of words is reached
    # restart search on stop words like RT, @xxx, URLs
    (content || "").split(" ").each do |word|
      reset = false;
      [/^rt[^\w]?$/i, /^@\w+[^\w]?$/, /^http:\/\//i].each{|p| reset = true if word =~ p}
      words = [] and next if reset
      words << word
      break if words.size >= 8
    end
    words.size >= 8 ? words.join(" ") : nil
  end
  
  # source type or nil if no source
  def sourcetype
    source ? source.kind : nil
  end
  
  # source name or nil if no source
  def sourcename
    source ? source.name : nil
  end
  
  # author or empty string of no author
  def authorname
    author || ""
  end

  private
    # strips any html from the content and title
    def strip_html
      self.content = strip_tags(content)
      self.title = strip_tags(title)
    end
end
